package sf.dsl.example;

import sf.core.DBField;
import sf.database.dialect.DBDialect;
import sf.database.jdbc.sql.SQLParameter;
import sf.database.meta.ColumnMapping;
import sf.database.meta.EntityUtils;
import sf.tools.StringUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class SimpleField implements IField, Serializable {
    //专门属性
    protected ColumnMapping columnMapping;
    protected DBField field;
    //下面为公共属性
    /**
     * 对应表关系
     */
    protected SimpleTable table;
    /**
     * 表别名
     */
    protected String tableAlias;
    /**
     * 数据库列名
     */
    protected String name;
    /**
     * 列别名
     */
    protected String alias;

    public SimpleField() {
    }

    /**
     * 字段名称
     * @param name
     */
    public SimpleField(String name) {
        this.name = name;
    }

    /**
     * @param tableAlias 表别名
     * @param name       字段名称
     * @param alias      字段别名
     */
    public SimpleField(String tableAlias, String name, String alias) {
        this.tableAlias = tableAlias;
        this.name = name;
        this.alias = alias;
    }

    public static SimpleField create(DBField property) {
        ColumnMapping columnMapping = EntityUtils.getColumn(property);
        return create(columnMapping);
    }

    public static SimpleField create(ColumnMapping columnMapping) {
        SimpleField column = new SimpleField();
        column.setTable(new SimpleTable(columnMapping.getMeta()));
        column.setColumnMapping(columnMapping);
        column.setName(columnMapping.getRawColumnName());
        column.setField(columnMapping.getField());
        return column;
    }

    public SimpleField as(String alias) {
        this.alias = alias;
        return this;
    }

    public SimpleField tableAlias(String tableAlias) {
        this.tableAlias = tableAlias;
        return this;
    }

    protected ICondition addCondition(String condition) {
        return QPI.addCondition(condition);
    }

    protected ICondition addCondition(DBOperator operator) {
        return QPI.addCondition(this, operator);
    }

    protected ICondition addCondition(String condition, Collection<?> values) {
        return QPI.addCondition(condition, values);
    }

    protected ICondition addCondition(DBOperator operator, Object value) {
        return QPI.addCondition(this, operator, value);
    }

    /**
     * @param operator
     * @param value
     * @param defaultValue 填充相等或不相等条件,true是,false为否
     * @return
     */
    protected ICondition addConditionArray(DBOperator operator, Object value, boolean defaultValue) {
        return QPI.addConditionArray(this, operator, value, defaultValue);
    }

    protected ICondition addConditionBetween(DBOperator operator, Object value1, Object value2) {
        return QPI.addConditionBetween(this, operator, value1, value2);
    }

    /**
     * @return
     */
    public ICondition isNull() {
        return addCondition(DBOperator.IS_NULL);
    }

    /**
     * @return
     */
    public ICondition isNotNull() {
        return addCondition(DBOperator.IS_NOT_NULL);
    }

    /**
     * 条件 =
     * @param value
     * @return
     */
    public ICondition eq(Object value) {
        return addCondition(DBOperator.EQUALS, value);
    }

    /**
     * 条件 <>
     * @param value
     * @return
     */
    public ICondition ne(Object value) {
        return addCondition(DBOperator.NOT_EQUALS, value);
    }

    /**
     * 条件 >
     * @param value
     * @return
     */
    public ICondition gt(Object value) {
        return addCondition(DBOperator.GREAT, value);
    }

    /**
     * 条件 >=
     * @param value
     * @return
     */
    public ICondition ge(Object value) {
        return addCondition(DBOperator.GREAT_EQUALS, value);
    }

    /**
     * 条件 <
     * @param value
     * @return
     */
    public ICondition lt(Object value) {
        return addCondition(DBOperator.LESS, value);
    }

    /**
     * 条件 <=
     * @param value
     * @return
     */
    public ICondition le(Object value) {
        return addCondition(DBOperator.LESS_EQUALS, value);
    }

    /**
     * 条件 in 子查询
     * @param value
     * @return
     */
    public ICondition in(Object value) {
        // 对于空集合的IN条件为永假
        ICondition c = null;
        if (value == null) {
            c = QPI.falseCondition();
        } else {
            c = addCondition(DBOperator.IN, value);
        }
        return c;
    }

    /**
     * 条件 in 多值
     * @param values
     * @return
     */
    public ICondition in(Collection<?> values) {
        // 对于空集合的IN条件为永假
        return addConditionArray(DBOperator.IN, values, false);
    }

    /**
     * 条件 in 多值
     * @param values
     * @return
     */
    public ICondition in(Object... values) {
        // 对于空集合的IN条件为永假
        return addConditionArray(DBOperator.IN, values, false);
    }


    /**
     * 条件 not in 多值
     * @param values
     * @return
     */
    public ICondition notIn(Collection<?> values) {
        // 对于空集合的NOT IN条件为永真
        return addConditionArray(DBOperator.NOT_IN, values, true);
    }

    /**
     * 条件 not in 多值
     * @param values
     * @return
     */
    public ICondition notIn(Object... values) {
        // 对于空集合的NOT IN条件为永真
        return addConditionArray(DBOperator.NOT_IN, values, true);
    }

    /**
     * 条件 not in 子查询
     * @param value
     * @return
     */
    public ICondition notIn(Object value) {
        // 对于空集合的IN条件为永真
        ICondition c = null;
        if (value == null) {
            c = QPI.trueCondition();
        } else {
            c = addCondition(DBOperator.NOT_IN, value);
        }
        return c;
    }

    public ICondition between(Object value1, Object value2) {
        return addConditionBetween(DBOperator.BETWEEN, value1, value2);
    }

    public ICondition notBetween(Object value1, Object value2) {
        return addConditionBetween(DBOperator.NOT_BETWEEN, value1, value2);
    }

    public ICondition like(String value) {
        return addCondition(DBOperator.LIKE, value);
    }

    public ICondition like(String value, char escape) {
        ICondition c = addCondition(DBOperator.LIKE_ESCAPE, value);
        if (c instanceof PartCondition) {
            ((PartCondition) c).setEscape(String.valueOf(escape));
        }
        return c;
    }

    public ICondition like(String value, boolean escape) {
        return addCondition((escape ? DBOperator.LIKE_ESCAPE : DBOperator.LIKE), value);
    }

    public ICondition notLike(String value) {
        return addConditionBetween(null, DBOperator.NOT_LIKE, value);
    }

    public ICondition notLike(String value, char escape) {
        ICondition c = addCondition(DBOperator.NOT_LIKE, value);
        if (c instanceof PartCondition) {
            ((PartCondition) c).setEscape(String.valueOf(escape));
        }
        return c;
    }

    public ICondition notLike(String value, boolean escape) {
        return addCondition((escape ? DBOperator.NOT_LIKE_ESCAPE : DBOperator.NOT_LIKE), value);
    }

    protected String wrap(DBDialect dialect, String table, String column) {
        if (dialect != null) {
            table = dialect.wrapKeyword(table);
            column = dialect.wrapKeyword(column);
        }
        if (StringUtils.isNotBlank(table)) {
            return table + "." + column;
        } else {
            return column;
        }
    }

    /**
     * 条件字段,忽略字段别名
     * @param useDefaultTableNameAlias 使用默认的表名当作别名
     * @param dialect
     */
    @Override
    public void toConditionSql(StringBuilder sb, List<SQLParameter> list, AtomicBoolean useDefaultTableNameAlias, boolean useTablePrefix, DBDialect dialect) {
        boolean bool = false;
        if (useDefaultTableNameAlias != null) {
            bool = useDefaultTableNameAlias.get();
        }
        String tableAlias = getTableAlias();
        if (getTable() != null) {
            if (StringUtils.isBlank(tableAlias) && StringUtils.isNotBlank(getTable().getTableAlias())) {
                tableAlias = getTable().getTableAlias();
            }
            if (StringUtils.isBlank(tableAlias) && bool) {
                tableAlias = getTable().getTableName();
            }
        }
        String columnName = getName();
        if (StringUtils.isBlank(columnName)) {
            if (getColumnMapping() != null) {
                columnName = getColumnMapping().getRawColumnName();
            }
        }
        if (dialect != null) {
            columnName = dialect.wrapKeyword(columnName);
            tableAlias = dialect.wrapKeyword(tableAlias);
        }
        if (StringUtils.isNotBlank(tableAlias) && useTablePrefix) {
            columnName = tableAlias + "." + columnName;
        }
        sb.append(columnName);
    }

    /**
     * 查询字段,需要加字段别名
     * @param useDefaultTableNameAlias 使用表名当做别名
     * @param dialect
     * @return
     */
    @Override
    public void toSelectSql(StringBuilder sb, List<SQLParameter> list, AtomicBoolean useDefaultTableNameAlias, DBDialect dialect) {
        String alias = getAlias();
        toConditionSql(sb, list, useDefaultTableNameAlias, true, dialect);
        if (dialect != null) {
            alias = dialect.wrapKeyword(alias);
        }
        if (StringUtils.isNotBlank(alias)) {
            sb.append(" as ").append(alias);
        }
    }

    public ColumnMapping getColumnMapping() {
        return columnMapping;
    }

    public void setColumnMapping(ColumnMapping columnMapping) {
        this.columnMapping = columnMapping;
    }

    public SimpleTable getTable() {
        return table;
    }

    public void setTable(SimpleTable table) {
        this.table = table;
    }

    public DBField getField() {
        return field;
    }

    public void setField(DBField field) {
        this.field = field;
    }

    public String getTableAlias() {
        return tableAlias;
    }

    public void setTableAlias(String tableAlias) {
        this.tableAlias = tableAlias;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }
}
